# Create your views here.
import json
import re
import logging

from django.conf import settings
from django.shortcuts import render, get_object_or_404
from django.shortcuts import render
from django.views import View, generic
from dj_youkou import constant
from news.models import Tag, Article, HotArticle, Banner, Comment
from news.serializers import TagSerializer, ArticleSerializer, CommentSerializer
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from utils.res_code.status_code import Code, error_map
from utils.res_code.status_json import status_json
from django.http import Http404, HttpResponseNotFound
from haystack.views import SearchView as _SearchView

logger = logging.getLogger('django')


class IndexView(View):
    """
    主页视图函数,返回tag标签
    """

    def get(self, request):
        # 返回tag的标签名
        tags = Tag.objects.only('name').filter(is_delete=False).all()
        hot_articles = HotArticle.objects.select_related('article').only('article__title', 'article__thumbnail').filter(
            is_delete=False).all()[:constant.PER_PAGE_SHOW_HOTARTICLE]
        banners = Banner.objects.filter(is_delete=False).all()[:constant.PER_PAGE_SHOW_BANNER]
        # serializer=TagSerializer(tags,many=True)
        # print(serializer.data)
        return render(request, 'news/index.html', locals())


class ArticleListView(View):
    """
    文章列表相关View
    """

    def get(self, request):
        try:
            # 获取首页的tag_id
            tag_id = int(request.GET.get('tag_id', 0))
        except Exception as e:
            logger.error('获取新闻标签id错误：{}'.format(e))
            tag_id = 0

        try:
            # 获取首页的文章的页码数
            page = int(request.GET.get('page', 1))
        except Exception as e:
            logger.error('获取新闻页码错误：{}'.format(e))
            page = 1

        articles_queryset = Article.objects.select_related('author', 'tag').only('title', 'digest', 'create_time',
                                                                                 'thumbnail', 'author__username',
                                                                                 'tag__name')
        # select_related: 表之间进行join连表操作，一次性获取关联的数据。
        # prefetch_related: 多表连表操作时速度会慢，使用其执行多次SQL
        #                   查询在Python代码中实现连表操作。分别在多个表中查询得到结果，然后重组。
        # only: 指挥查询only参数中的字段
        # defer：排除不需要的字段

        articles = articles_queryset.filter(is_delete=False).all() if tag_id == 0 else articles_queryset.filter(
            is_delete=False, tag_id=tag_id).all()
        # 获取tag_id对应的文章
        paginator = Paginator(articles, per_page=constant.PER_PAGE_SHOW_NUM)

        # Django自带的分页器
        """
        ###  from django.core.paginator import Paginator  django自带的分页器
        p = Paginator(obj, n)
        n == > 表示一页数据量
        1.count 总数
        2.num_pages页数
        3.page_range可以迭代的总页数 （1，16）
        4.page(n)第几页数据
        page1 = p.page(n)
        n == > 表示第几页
        1.object_list获取当页数据
        2.has_next是否具有下一页
        3.has_previous是否具有上一页
        4.has_other_pages是否具有其它页面
        5.next_page_number下一页的页码
        6.previous_page_number上一页的页码
        7.number当前第几页
        8.start_index数据开始的索引
        9.end_index数据结束的索引
        """
        try:
            page = paginator.page(number=page)
            serializer = ArticleSerializer(page, many=True)
            data = serializer.data
            # 对返回的该页数据进行序列化
            return status_json(data=data)
        except EmptyPage:
            # 若访问的页数为不存在,返回最后一页,并设置一个错误码
            page = paginator.page(number=paginator.num_pages)
            serializer = ArticleSerializer(page, many=True)
            data = serializer.data
            # 对返回的该页数据进行序列化
            return status_json(no=Code.PARAMERR, data=data, msg="已无更多文章")


class ArticleDetailsView(View):
    """
    文章详情
    """

    def get(self, request, article_id):
        article = Article.objects.select_related('tag', 'author'). \
            only('content', 'update_time', 'author__username',
                 'tag__name').filter(is_delete=False, id=article_id).first()
        if not article:
            # raise Http404("<新闻{}>不存在😢".format(article_id))
            return HttpResponseNotFound("<h1 style='color:red'><新闻{}>不存在😢</h1>".format(article_id))

        comments = Comment.objects.select_related('author', 'parent'). \
            only('content', 'update_time', 'author__username',
                 'parent__author__username',
                 'parent__content',
                 'parent__update_time').filter(is_delete=False, news_id=article_id)

        # 如果文章存在则查询文章的全部评论
        return render(request, 'news/news_detail.html', locals())


class ArticleCommentsView(View):
    """
    文章评论部分
    """

    def post(self, request, article_id):
        if not Article.objects.only('id').filter(is_delete=False, id=article_id).exists():
            # 判断文章是否存在
            return status_json(no=Code.PARAMERR, msg="文章不存在")
        if not request.user.is_authenticated:
            # 判断用户是否登录
            return status_json(errno=Code.SESSIONERR, msg=error_map[Code.SESSIONERR])

        json_data = request.body
        if not json_data:
            return status_json(no=Code.PARAMERR, msg=error_map[Code.PARAMERR])
        json_dict = json.loads(json_data.decode('utf-8'))
        content = json_dict.get('content')
        parent_id = json_dict.get('parent_id', None)

        if not content or re.match(r'^[ ]+$', content):
            # 判断所传来评论内容是否为空
            return status_json(no=Code.PARAMERR, msg="评论不能为空")
        comment = Comment()
        comment.author = request.user
        comment.content = content
        comment.parent_id = int(parent_id) if parent_id else None
        comment.news_id = article_id
        comment.save()
        # 存储数据到数据库
        data = comment.to_dict_data()
        # data为序列化之后的数据
        return status_json(msg="评论成功", data=data)


class SearchView(_SearchView):
    """
    重写响应方式，如果请求参数q为空，返回模型News的热门文章数据，否则根据参数q搜索相关数据
    """

    template = 'news/search.html'

    def create_response(self):
        v = self.request.GET.get('q', '')
        if not v:
            show_all = True
            hot_articles = HotArticle.objects.select_related('article', 'article__author', 'article__tag').only \
                ('article__title', 'article__tag__name', 'article__digest', 'article__update_time',
                 'article__author__username').filter(is_delete=False).order_by('-article__clicks')
            paginator = Paginator(object_list=hot_articles, per_page=settings.HAYSTACK_SEARCH_RESULTS_PER_PAGE)
            try:
                page = paginator.page(int(self.request.GET.get('page', '1')))
            except EmptyPage:
                # 当page超出范围时返回最后一页
                page = paginator.page(paginator.num_pages)
            except PageNotAnInteger:
                # 当page不是一个整数时，返回第一页
                page = paginator.page(1)
            finally:
                return render(self.request, self.template, locals())
        else:
            show_all = False
            return super().create_response()
